/*Copyright ©2015 TommyLemon(https://github.com/TommyLemon)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
limitations under the License.*/

package zuo.biao.library.base;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.LayoutScatter;
import ohos.global.resource.Element;
import ohos.global.resource.NotExistException;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import zuo.biao.library.util.CommonUtil;
import zuo.biao.library.util.Log;
import zuo.biao.library.util.ResTUtil;

import java.io.IOException;

/**基础自定义View，适合任何View
 * <br /> 可以用于Adapter内的ItemView，也可以单独作为一个组件使用
 * @author Lemon
 * @param <T> 数据模型(model/JavaBean)类
 * @see #onDataChangedListener
 * @see #onDestroy
 * @use extends BaseView<T>, 具体参考.DemoView
 */
public abstract class BaseView<T> {
    private static final String TAG = "BaseView";
    Component itemView;
    /**
     * 点击事件
     */
    public interface OnViewClickListener {
        /**
         * 点击事件
         * @param bv  b
         * @param v v
         */
        void onViewClick(BaseView bv, Component v); // BaseView<T>泛型太麻烦，不利于多层View传递
    }

    /**数据改变回调接口
     * (Object) getData() - 改变的数据
     */
    public interface OnDataChangedListener {
        void onDataChanged();
    }

    /**
     * 需要在BaseView子类手动回调 onViewClickListener.onViewClick(...)
     */
    public OnViewClickListener onViewClickListener; // 数据改变回调监听回调的实例

    public BaseView<T> setOnViewClickListener(OnViewClickListener onViewClickListener) {
        this.onViewClickListener = onViewClickListener;
        return this;
    }

    /**
     * 需要在BaseView子类手动回调 onViewClickListener.onDataChanged()
     */
    public OnDataChangedListener onDataChangedListener; // 数据改变回调监听回调的实例
    /**
     * 设置数据改变事件监听回调
     * @param listener listener
     * @return BaseView
     */
    public BaseView<T> setOnDataChangedListener(OnDataChangedListener listener) {
        onDataChangedListener = listener;
        return this;
    }

    /**
     * BaseView
     * @param context context
     * @param layoutResId layoutResId
     *
     */
    public BaseView(Ability context, int layoutResId) {
        this(context, layoutResId, null);
    }

    /**
     * @param context context
     * @param layoutResId layoutResId
     * @param parent  如果itemView不能占满宽度 或 高度不对，一般是RecyclerView的问题，可通过传parent解决
     */
    public BaseView(Ability context, int layoutResId, ComponentContainer parent) {
        this(context, (ComponentContainer) LayoutScatter.getInstance(context).parse(layoutResId, parent, false));
    }
    /**
     * 传入的Activity,可在子类直接使用
     */
    public final Ability context;
    /**
     * @param context context
     * @param itemView itemView
     */
    public BaseView(Ability context, ComponentContainer itemView) {
        this.context = context;
    }

    /**通过id查找并获取控件，使用时不需要强转
     * @param id id
     * @return findView
     */
    public <V extends Component> V findView(int id) {
        return (V) itemView.findComponentById(id);
    }
    /**通过id查找并获取控件，使用时不需要强转
     * @param id id
     * @return findViewById
     */
    public <V extends Component> V findViewById(int id) {
        return findView(id);
    }
    /**通过id查找并获取控件，并setOnClickListener
     * @param id id
     * @param listener listener
     * @return findView
     */
    public <V extends Component> V findView(int id, Component.ClickedListener listener) {
        V v = findView(id);
        v.setClickedListener(listener);
        return v;
    }
    /**通过id查找并获取控件，并setOnClickListener
     * @param id id
     * @param listener listener
     * @return findViewById
     */
    public <V extends Component> V findViewById(int id, Component.ClickedListener listener) {
        return findView(id, listener);
    }

    /**
     * 基础数据
     */
    public T data = null;
    /**
     * data在列表中的位置
     * @must 只使用bindView(int position, T data)方法来设置position，保证position与data对应正确
     */
    public int position = 0;
    /**
     * 视图类型，部分情况下需要根据viewType使用不同layout，对应Adapter的itemViewType
     */
    public int viewType = 0;
    /**
     * 是否已被选中
     */
    public boolean selected = false;

    /**创建一个新的View
     * @return Component
     */
    public Component createView() {
        return itemView;
    }

    /**获取itemView的宽度
     * @warn 只能在createView后使用
     * @return int
     */
    public int getWidth() {
        return itemView.getWidth();
    }
    /**获取itemView的高度
     * @warn 只能在createView后使用
     * @return int
     */
    public int getHeight() {
        return itemView.getHeight();
    }

    /**设置并显示内容，建议在子类bindView内this.data = data;
     * @warn 只能在createView后使用
     * @param data - 传入的数据
     * @param position - data在列表中的位置
     * @param viewType - 视图类型，部分情况下需要根据viewType使用不同layout
     */
    public void bindView(T data, int position, int viewType) {
        this.position = position;
        this.viewType = viewType;
        bindView(data);
    }
    /**设置并显示内容，建议在子类bindView内this.data = data;
     * @warn 只能在createView后使用
     * @param data_ - 传入的数据
     */
    public void bindView(T data_) {
        if (data_ == null) {
            Log.warn(TAG, "bindView data_ == null");
        }
        this.data = data_;

        // 不一定要用单选功能，实现也不一定要用这种方式，这里写会影响所有BaseView子类的性能，子类写更好 itemView.setSelected(selected);
    }

    /**获取可见性
     * @warn 只能在createView后使用
     * @return 可见性 (View.VISIBLE, View.GONE, View.INVISIBLE);
     */
    public int getVisibility() {
        return itemView.getVisibility();
    }
    /**设置可见性
     * @warn 只能在createView后使用
     * @param visibility - 可见性 (View.VISIBLE, View.GONE, View.INVISIBLE);
     */
    public void setVisibility(int visibility) {
        itemView.setVisibility(visibility);
    }

    /**设置背景
     * @warn 只能在createView后使用
     * @param resId resId
     */
    public void setBackground(int resId) {
        itemView.setBackground(ResTUtil.getElement(context, resId));
    }


    // resources方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    /**
     * 资源管理器
     */
    public ResourceManager resources;
    /**
     * 获取资源管理器
     * @return 资源管理器
     */
    public final ResourceManager getResources() {
        if (resources == null) {
            resources = context.getResourceManager();
        }
        return resources;
    }

    /**
     * stringId
     * @param id id
     * @return str
     */
    public String getString(int id) {
        return ResTUtil.getString(context, id);
    }

    /**
     * 获取颜色
     * @param id id
     * @return int
     */
    public int getColor(int id) {
        return ResTUtil.getColor(context, id);
    }

    /**
     * 获取资源
     * @param id id
     * @return e
     */
    public Element getDrawable(int id) {
        try {
            return getResources().getElement(id);
        } catch (IOException e) {
            Log.error("IOException", e.getMessage());
        } catch (NotExistException e) {
            Log.error("NotExistException", e.getMessage());
        } catch (WrongTypeException e) {
            Log.error("WrongTypeException", e.getMessage());
        }
        return null;
    }

    /**
     * 获取dimen
     * @param id id
     * @return float
     */
    public float getDimension(int id) {
        return ResTUtil.getDimen(context, id);
    }
    // resources方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    // show short toast 方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    /**快捷显示short toast方法，需要long toast就用 Toast.makeText(string, Toast.LENGTH_LONG).show(); ---不常用所以这个类里不写
     * @param stringResId stringResId
     */
    public void showShortToast(int stringResId) {
        CommonUtil.showShortToast(context, stringResId);
    }
    /**快捷显示short toast方法，需要long toast就用 Toast.makeText(string, Toast.LENGTH_LONG).show(); ---不常用所以这个类里不写
     * @param string string
     */
    public void showShortToast(String string) {
        CommonUtil.showShortToast(context, string);
    }
    // show short toast 方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    // 启动新Activity方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    /**打开新的Activity，向左滑入效果
     * @param intent intent
     */
    public void toActivity(final Intent intent) {
        CommonUtil.toActivity(context, intent);
    }
    /**打开新的Activity
     * @param intent intent
     * @param showAnimation showAnimation
     */
    public void toActivity(final Intent intent, final boolean showAnimation) {
        CommonUtil.toActivity(context, intent, showAnimation);
    }
    /**打开新的Activity，向左滑入效果
     * @param intent intent
     * @param requestCode requestCode
     */
    public void toActivity(final Intent intent, final int requestCode) {
        CommonUtil.toActivity(context, intent, requestCode);
    }
    /**打开新的Activity
     * @param intent intent
     * @param requestCode requestCode
     * @param showAnimation showAnimation
     */
    public void toActivity(final Intent intent, final int requestCode, final boolean showAnimation) {
        CommonUtil.toActivity(context, intent, requestCode, showAnimation);
    }
    // 启动新Activity方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    /**销毁并回收内存，建议在对应的View占用大量内存时使用
     * @warn 只能在UI线程中调用
     */
    public void onDestroy() {
        if (itemView != null) {
            try {
                itemView = null;
            } catch (Exception e) {
                Log.warn(
                        TAG,
                        "onDestroy  try { itemView.destroyDrawingCache();"
                                + " >> } catch (Exception e) {"
                                + e.getMessage());
            }
        }

        onDataChangedListener = null;

        data = null;
        position = 0;
    }
}
